package org.kwin.spring.context;

import org.kwin.common.util.RefectUtil;
import org.kwin.spring.aop.annotation.EnableAspectJAutoProxy;
import org.kwin.spring.beans.annotation.Import;
import org.kwin.spring.jdbc.config.OrmAutoConfigure;
import org.kwin.springboot.annotation.SpringBootApplication;

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Map;
import java.util.Properties;

/**
 * @author : wangkai
 * @version V1.0
 * @Package org.kwin.spring.context
 * @Description:
 * @date 2021年09月28日 11:12
 **/
public class GenericApplicationContext extends ActionApplicationContext implements ApplicationContext {
    
    protected GenericApplicationContext() {
    }
    
    /**
     * 加载容器，注册组件
     * @param clzz
     * @param properties
     */
    protected void loadApplicationContext(Class<?> clzz, Properties properties)
    {
        if(!validSpring(clzz)) {
            System.err.println("not spring boot app");
            return;
        }
        
        // 扫描组件
        this.scanComponent(clzz, properties);
        
        // 自定义import扫描组件,如orm框架
        this.autoImport(clzz, properties);
    
        // 注入组件
        super.autowiredComponent(this);
        
        // 启用切面
        if(clzz.isAnnotationPresent(EnableAspectJAutoProxy.class)) {
            // 加载切面、事务代理组件
            super.loadAspect();
            
            // 绑定代理
            super.autowiredProxy();
        }
        
    }
    
    /**
     * 校验是否springboot项目
     * @param clzz
     * @return
     */
    private boolean validSpring(Class<?> clzz) {
    
        return clzz.isAnnotationPresent(SpringBootApplication.class);
    }
    
    
    private void autoImport(Class clzz, Properties properties) {
        Annotation[] annotations = clzz.getAnnotations();
        if(annotations == null || annotations.length == 0) {
            return;
        }
        for(Annotation annotation : annotations) {
            if(annotation.annotationType().isAnnotationPresent(Import.class)) {
                Import impor = annotation.annotationType().getAnnotation(Import.class);
                importOrm(impor, annotation, properties);
            }
        }
    }
    
    private void importOrm(Import impor, Annotation annotation, Properties properties) {
        Class[] clzzes = impor.value();
        if(clzzes == null || clzzes.length == 0) {
            return;
        }
        
        for(Class clzz : clzzes) {
            if(OrmAutoConfigure.class.isAssignableFrom(clzz)) {
                OrmAutoConfigure ormAutoConfigure = RefectUtil.newInstance(clzz);
                if(ormAutoConfigure != null) {
                    ormAutoConfigure.auto(this, annotation, properties);
                }
                
            }
        }
    }
    
    @Override
    public Object getBean(String name) {
        return beanMap.get(name);
    }
    
    @Override
    public <T> T getBean(String name, Class<T> requiredType) {
        return (T) beanMap.get(name);
    }
    
    @Override
    public Object getBean(String name, Object... args) {
        return null;
    }
    
    @Override
    public <T> T getBean(Class<T> requiredType) {
        return getBeanByType(requiredType, true);
    }
    
    @Override
    public <T> T getBean(Class<T> requiredType, Object... args) {
        return null;
    }
    
    @Override
    public boolean containsBean(String name) {
        return false;
    }
    
    @Override
    public boolean isSingleton(String name) {
        return false;
    }
    
    @Override
    public boolean isPrototype(String name) {
        return false;
    }
    
    @Override
    public boolean isTypeMatch(String name, Class<?> typeToMatch) {
        return false;
    }
    
    @Override
    public Class<?> getType(String name) {
        return null;
    }
    
    @Override
    public String[] getAliases(String name) {
        return new String[0];
    }
    
    /**
     * 注册一个bean
     *
     * @param name
     * @param bean
     * @return
     */
    @Override
    public boolean register(String name, Object bean) {
        return beanMap.put(name, bean) == null;
    }
    
    /**
     * 根据name删除一个Bean
     *
     * @param name
     * @return
     */
    @Override
    public boolean remove(String name) {
        return false;
    }
    
    /**
     * 根据类型删除一个bean
     *
     * @param requiredType
     * @return
     */
    @Override
    public boolean remove(Class<?> requiredType) {
        return false;
    }
    
    /**
     * 获取IOC容器
     *
     * @return
     */
    @Override
    public Map<String, Object> getIoc() {
        return beanMap;
    }
    

    /**
     * 根据类型返回Bean
     * @param clzz
     * @param bySuper 是否可通过超类检查bean
     * @param <T>
     * @return
     */
    private <T> T getBeanByType(Class<T> clzz, boolean bySuper)
    {
        Collection<Object> values = beanMap.values();
        for (Object o : values)
        {
            if (o.getClass() == clzz)
            {
                return (T) o;
            }
        }
        if (!bySuper)
        {
            return null;
        }
        return getBeanBySubclass(clzz);
    }
    
    /**
     * 根据类型返回子类bean
     *
     * @param clzz
     * @param <T>
     * @return
     */
    private <T> T getBeanBySubclass(Class<T> clzz)
    {
        for (Object obj : beanMap.values())
        {
            if (obj.getClass().getSuperclass() == clzz)
            {
                return (T) obj;
            }
            for (Class clazz : obj.getClass().getInterfaces())
            {
                if (clazz == clzz)
                {
                    return (T) obj;
                }
            }
        }
        return null;
    }
}
